#!/usr/bin/python3
#-*- coding: utf-8 -*-

from ctypes.wintypes import BOOL, BYTE, CHAR, COLORREF, DOUBLE, DWORD, FLOAT, HANDLE, HDC, HBRUSH, HMONITOR, HWND, INT, LONG, LPCSTR, LPLONG, LPRECT, RECT, UINT, PUINT, WPARAM
from ctypes import (windll, WINFUNCTYPE, POINTER, Structure, WinError, pointer, byref, cast, addressof, GetLastError,
                    c_bool, c_char, c_wchar, c_short, c_ushort,
                    c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong,
                    c_float, c_double, c_char_p, c_wchar_p, c_void_p
                    )

kernel32 = windll.kernel32
user32 = windll.user32
gdi32 = windll.gdi32


# HWND FindWindowExA(
#   [in, optional] HWND   hWndParent,
#   [in, optional] HWND   hWndChildAfter,
#   [in, optional] LPCSTR lpszClass,
#   [in, optional] LPCSTR lpszWindow
# );
FindWindowEx = WINFUNCTYPE(HWND, HWND, HWND, LPCSTR, LPCSTR)(('FindWindowExA', user32)) 
# paramflags=((IN, 'hWndParent'), (IN, 'hWndChildAfter', HWND()), (IN, 'lpszClass'), (IN, 'lpszWindow')))


# BOOL SetWindowPos(
#   [in]           HWND hWnd,
#   [in, optional] HWND hWndInsertAfter,
#   [in]           int  X,
#   [in]           int  Y,
#   [in]           int  cx,
#   [in]           int  cy,
#   [in]           UINT uFlags
# );
SetWindowPos = WINFUNCTYPE(BOOL, HWND, HWND, c_int, c_int, c_int, c_int, UINT)(('SetWindowPos', user32))
# 值 	含义
SWP_ASYNCWINDOWPOS = UINT( 0x4000)  # 如果调用线程和拥有窗口的线程附加到不同的输入队列，则系统会将请求发布到拥有窗口的线程。 这可以防止调用线程阻止其执行，而其他线程处理请求。
SWP_DEFERERASE = UINT( 0x2000)  # 阻止生成 WM_SYNCPAINT 消息。
SWP_DRAWFRAME = UINT( 0x0020)  # 在窗口的类说明) 围绕窗口绘制 (定义的框架。
SWP_FRAMECHANGED = UINT( 0x0020)  # 使用 SetWindowLong 函数应用新框架样式集。 向窗口发送 WM_NCCALCSIZE 消息，即使窗口的大小未更改也是如此。 如果未指定此标志，则仅在更改窗口大小时发送 WM_NCCALCSIZE 。
SWP_HIDEWINDOW = UINT( 0x0080)  # 隐藏窗口。
SWP_NOACTIVATE = UINT( 0x0010)  # 不激活窗口。 如果未设置此标志，则会激活窗口并将其移动到最顶层或非最顶部组 (的顶部，具体取决于 hWndInsertAfter 参数) 的设置。
SWP_NOCOPYBITS = UINT( 0x0100)  # 丢弃工作区的整个内容。 如果未指定此标志，则会保存工作区的有效内容，并在调整窗口大小或重新定位后复制回工作区。
SWP_NOMOVE = UINT( 0x0002)  # 保留当前位置 (忽略 X 和 Y 参数) 。
SWP_NOOWNERZORDER = UINT( 0x0200)  # 不更改所有者窗口在 Z 顺序中的位置。
SWP_NOREDRAW = UINT( 0x0008)  # 不重绘更改。 如果设置了此标志，则不执行任何形式的重绘。 这适用于工作区、非工作区 (包括标题栏和滚动条) ，以及由于窗口移动而发现父窗口的任何部分。 设置此标志后，应用程序必须显式使需要重绘的窗口和父窗口的任何部分失效或重绘。
SWP_NOREPOSITION = UINT( 0x0200)  # 与 SWP_NOOWNERZORDER 标志相同。
SWP_NOSENDCHANGING = UINT( 0x0400)  # 阻止窗口接收 WM_WINDOWPOSCHANGING 消息。
SWP_NOSIZE = UINT( 0x0001)  # 保留当前大小 (忽略 cx 和 cy 参数) 。
SWP_NOZORDER = UINT( 0x0004)  # 保留当前 Z 顺序 (忽略 hWndInsertAfter 参数) 。
SWP_SHOWWINDOW = UINT( 0x0040)  # 显示“接收端口跟踪选项” 窗口。

# dc = GetDC(hTextArea);
GetDC = WINFUNCTYPE(HDC, HWND)(('GetDC', user32))

# int ReleaseDC(
#   [in] HWND hWnd,
#   [in] HDC  hDC
# );
ReleaseDC = WINFUNCTYPE(c_int, HWND, HDC)(('ReleaseDC', user32))

# BOOL GetWindowRect(
#   [in]  HWND   hWnd,
#   [out] LPRECT lpRect
# );
GetWindowRect = WINFUNCTYPE(BOOL, HWND, LPRECT)(('GetWindowRect', user32), 
        paramflags=((IN, 'hWnd'), (OUT, 'lpRect')))
def errcheck_GetWindowRect(result, func, args):
    if not result:
        raise WinError()
    return args
GetWindowRect.errcheck = errcheck_GetWindowRect

# HMONITOR MonitorFromRect(
#   [in] LPCRECT lprc,
#   [in] DWORD   dwFlags
# );
MonitorFromRect = WINFUNCTYPE(HMONITOR, LPRECT, DWORD)(('MonitorFromRect', user32))
MONITOR_DEFAULTTONEAREST = DWORD(0x00000002)
#define MONITOR_DEFAULTTONULL       0x00000000
#define MONITOR_DEFAULTTOPRIMARY    0x00000001
#define MONITOR_DEFAULTTONEAREST    0x00000002

# typedef struct tagMONITORINFO {
#   DWORD cbSize;
#   RECT  rcMonitor;
#   RECT  rcWork;
#   DWORD dwFlags;
# } MONITORINFO, *LPMONITORINFO;
class MONITORINFO(Structure):
    _fields_ = [
            ('cbSize', DWORD),
            ('rcMonitor', RECT),
            ('rcWork', RECT),
            ('dwFlags', DWORD)
            ]
    def __repr__(self):
        return f"""MONITORINFO(cbSize={
            self.cbSize
        }, rcMonitor={
            self.rcMonitor
        }, rcWork={
            self.rcWork
        }, dwFlags={
            self.dwFlags
        })"""


LPMONITORINFO = POINTER(MONITORINFO)

# BOOL GetMonitorInfoA(
#   [in]  HMONITOR      hMonitor,
#   [out] LPMONITORINFO lpmi
# );
GetMonitorInfo = WINFUNCTYPE(BOOL, HMONITOR, LPMONITORINFO)(('GetMonitorInfoA', user32))

# COLORREF GetPixel(
#   [in] HDC hdc,
#   [in] int x,
#   [in] int y
# );
GetPixel = WINFUNCTYPE(COLORREF, HDC, c_int, c_int)(('GetPixel', gdi32))

# COLORREF SetDCBrushColor(
#   [in] HDC      hdc,
#   [in] COLORREF color
# );
SetDCBrushColor = WINFUNCTYPE(COLORREF, HDC, COLORREF)(('SetDCBrushColor', gdi32))
CLR_INVALID = COLORREF(0xFFFFFFFF)

def IsFullScreen(hTextArea: HWND):
    '''
			MONITORINFO mi;
			HMONITOR hMonitor;
			long unsigned int z;
			char p[MAX_PATH];
			HDC dc;
			COLORREF rgb;
			dc = GetDC(hTextArea);
			if (dc != NULL) {
				GetWindowRect(hTextArea, &rc);
				rgb = GetPixel(dc, rc.right - rc.left - 4, rc.bottom - rc.top - 4);
				if (rgb != CLR_INVALID) {
					SetDCBrushColor(dc, rgb);
				}
				ReleaseDC(hTextArea, dc);
			}
			z = (long unsigned int)IsZoomed(hTop)?1:0;
			if(z) {
				SendMessage(hTop, WM_SYSCOMMAND, SC_RESTORE, 0);
			}
			GetWindowRect(hTop, &rc);
			sprintf(p, "gVim_Position=%ld\t%ld\t%ld\t%ld\t%d", rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, z);
			putenv(p);
			hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST);
			//
			// get the work area or entire monitor rect.
			//
			mi.cbSize = sizeof(mi);
			GetMonitorInfo(hMonitor, &mi);
			g_x = mi.rcMonitor.left;
			g_y = mi.rcMonitor.top;
			g_dx = mi.rcMonitor.right - g_x;
			g_dy = mi.rcMonitor.bottom - g_y;
			/* Remove border, caption, and edges */
			SetWindowLong(hTop, GWL_STYLE, GetWindowLong(hTop, GWL_EXSTYLE) & ~WS_BORDER);
			SetWindowLong(hTop, GWL_STYLE, GetWindowLong(hTop, GWL_STYLE) & ~WS_CAPTION);
			SetWindowLong(hTop, GWL_EXSTYLE, GetWindowLong(hTop, GWL_STYLE) & ~WS_EX_CLIENTEDGE);
			SetWindowLong(hTop, GWL_EXSTYLE, GetWindowLong(hTop, GWL_STYLE) & ~WS_EX_WINDOWEDGE);
			SetWindowPos(hTop, HWND_TOP, g_x, g_y, g_dx, g_dy, SWP_SHOWWINDOW);
			//sprintf(p, "%ld\t%ld\t%ld\t%ld", g_x, g_y, g_dx, g_dy, z);
			//SetWindowLong(hTextArea, GWL_EXSTYLE, GetWindowLong(hTextArea, GWL_EXSTYLE) & ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR));
			/*SetWindowLong(hTextArea, GWL_EXSTYLE, GetWindowLong(hTextArea, GWL_STYLE) & ~WS_EX_CLIENTEDGE);*/
			SetWindowLong(hTextArea, GWL_EXSTYLE, GetWindowLong(hTextArea, GWL_STYLE) & ~WS_EX_WINDOWEDGE);
			SetWindowPos(hTextArea, HWND_TOP, 0, 0, g_dx, g_dy, SWP_SHOWWINDOW);
    '''
    print(f"IsFullScreen({hTextArea})")
    dc = GetDC(hTextArea)
    if dc:
        ok = ReleaseDC(hTextArea, dc)
        print(f"ReleaseDC return {ok}")


hTop = GetTopWindow()
hTextArea = FindWindowEx(hTop, HWND(), b"VimTextArea", b"Vim text area")
# print(f"hTextArea = {hTextArea}")
winStyle = GetWindowLong(hTop, GWL_STYLE)
# print(f"winStyle = {hex(winStyle)}")
if winStyle & WS_CAPTION.value:
    dc = GetDC(hTextArea)
    rc = RECT()
    if dc: 
        GetWindowRect(hTextArea, byref(rc))
        rgb = GetPixel(dc, rc.right - rc.left - 4, rc.bottom - rc.top - 4);
        if rgb != CLR_INVALID:
            ok = SetDCBrushColor(dc, rgb)
        ok = ReleaseDC(hTextArea, dc)
    z = IsZoomed(hTop)
    if z :
        print("IsZoomed, restore")
        SendMessage(hTop, WM_SYSCOMMAND, SC_RESTORE, LONG(0))
    GetWindowRect(hTop, byref(rc))
    # print(f"rc = {rc.left, rc.top, rc.right, rc.bottom}")
    hMonitor = MonitorFromRect(byref(rc), MONITOR_DEFAULTTONEAREST)
    mi = MONITORINFO()
    GetMonitorInfo(hMonitor, byref(mi))
    # print(f"hMonitor = {hMonitor}, mi = {mi}")
    g_x = mi.rcMonitor.left;
    g_y = mi.rcMonitor.top;
    g_dx = mi.rcMonitor.right - g_x;
    g_dy = mi.rcMonitor.bottom - g_y;
    # /* Remove border, caption, and edges */
    exStyle = GetWindowLong(hTop, GWL_EXSTYLE)
    SetWindowLong(hTop, GWL_STYLE, exStyle & ~WS_BORDER.value)
    style = GetWindowLong(hTop, GWL_STYLE)
    SetWindowLong(hTop, GWL_STYLE, style & ~WS_CAPTION.value)
    style = GetWindowLong(hTop, GWL_STYLE)
    SetWindowLong(hTop, GWL_EXSTYLE, style & ~WS_EX_CLIENTEDGE.value)
    style = GetWindowLong(hTop, GWL_STYLE)
    SetWindowLong(hTop, GWL_EXSTYLE, style & ~WS_EX_WINDOWEDGE.value)
    SetWindowPos(hTop, HWND_TOP, g_x, g_y, g_dx, g_dy, SWP_SHOWWINDOW);
    # mask = ~(WS_EX_DLGMODALFRAME.value | WS_EX_CLIENTEDGE.value | WS_EX_WINDOWEDGE.value | WS_EX_RIGHTSCROLLBAR.value)
    # print(f"mask = {hex(mask)}")
    # SetWindowLong(hTextArea, GWL_EXSTYLE, GetWindowLong(hTextArea, GWL_EXSTYLE) & mask)
    # SetWindowLong(hTextArea, GWL_EXSTYLE, GetWindowLong(hTextArea, GWL_STYLE) & ~WS_EX_CLIENTEDGE.value)
    SetWindowLong(hTextArea, GWL_EXSTYLE, GetWindowLong(hTextArea, GWL_STYLE) & ~WS_EX_WINDOWEDGE.value)
    SetWindowPos(hTextArea, HWND_TOP, 0, 0, g_dx, g_dy, SWP_SHOWWINDOW)

